package jmine.tec.utils.collection.impl;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * 
 * @author takeshi
 * 
 * @param <K>
 * @param <V>
 */
public class MapCache<K, V> extends LinkedHashMap<K, V> implements Map<K, V> {

    /**
     * 
     */
    private static final long serialVersionUID = 6409024512669568042L;

    /**
     * The default initial capacity - MUST be a power of two.
     */
    static final int DEFAULT_INITIAL_CAPACITY = 16;

    /**
     * The load factor used when none specified in constructor.
     */
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    private final int maxSize;

    /**
     * 
     * @param maxSize
     *            int
     */
    public MapCache(final int maxSize) {
        super(maxSize, DEFAULT_LOAD_FACTOR, false);
        this.maxSize = maxSize;
    }

    /**
     * 
     * @param obj object
     * @return boolean
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @SuppressWarnings("unchecked")
    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
        if (!super.equals(obj)) {
            return false;
        }
        if (this.getClass() != obj.getClass()) {
            return false;
        }
        final MapCache<K, V> other = (MapCache<K, V>) obj;
        if (this.maxSize != other.maxSize) {
            return false;
        }
        final Set<Entry<K, V>> entrySet = this.entrySet();
        if (this.size() != other.size()) {
            return false;
        }
        for (Entry<K, V> entry : entrySet) {
            V v = other.get(entry.getKey());
            if (entry.getValue() != null) {
                if (!entry.getValue().equals(v)) {
                    return false;
                }
            } else if (v != null) {
                return false;
            }
        }
        return true;
    }

    /**
     * 
     * @return int
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = super.hashCode();
        result = prime * result + this.maxSize;
        return result;
    }

    /**
     * @param eldest
     *            entry
     * @return boolean
     */
    @Override
    protected boolean removeEldestEntry(final Entry<K, V> eldest) {
        return this.size() > this.maxSize;
    }

}
